package llm

import (
	"bytes"
	"dustbe/database"
	"dustbe/util"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

var UserName2LastPromptId = map[string]string{}
var PrivilegeUsersCache = map[string]bool{}
var UserStatus = map[string]bool{}

func contains(strings []string, target string) bool {
	for _, s := range strings {
		if target == s {
			return true
		}
	}
	return false
}


func checkPrivilegeBySession(c *gin.Context) error {
	session := sessions.Default(c)
	user := session.Get("user")
	if user != nil {
		userName := user.(string)
		
		// 先查看是否另一个同名服务正在开启
		_, has := UserStatus[userName]
		if has {
			return errors.New("你的另一个账号正在请求信息！")
		}

		// 检查权限，先查看缓存
		_, ok := PrivilegeUsersCache[userName]
		if ok {
			return nil
		}

		// 没有查看数据库
		privilegeUsers, err := database.GetLlmPrivilegeUsers()
		contained := contains(privilegeUsers, userName)
		
		if err != nil || !contained {
			return errors.New("权限不足")
		}
		// 满足权限加入缓存，下次就不需要查数据库了
		PrivilegeUsersCache[userName] = true

	} else {
		// 直接返回
		return errors.New("你还未登录！")
	}
	return nil
}

type ConversionItem struct {
	User string `json:"user"`
	Assistant string `json:"assistant"`
}

type ChatgptConversion struct {
	Data []ConversionItem `json:"data"`
}

func ResumeChatgptConversion(c *gin.Context) {
	ok := util.LimitIpInterval(c, 1)
	if !ok {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "太频繁了！"})
		return
	}

	err := checkPrivilegeBySession(c)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 300, "data": err.Error()})
		return
	}

	session := sessions.Default(c)
	userName := session.Get("user").(string)
	
	conversionPath := fmt.Sprintf("%s/chatgpt/%s.json", ConversionRoot, userName)
	
	ext, _ := util.CheckFilePath(conversionPath)
	if !ext {
		c.JSON(http.StatusOK, gin.H{"code": 500, "data": "对话数据不存在，开始新的对话吧！"})
		return
	}

	file, err := os.Open(conversionPath)	
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "打开本地json出错"})
		return
	}
	defer file.Close()
	
	data, err := ioutil.ReadAll(file)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "读取本地json出错"})
		return
	}

	var chatgptConversion ChatgptConversion
	err = json.Unmarshal(data, &chatgptConversion)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "解析本地json出错"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"code": 200, "data": chatgptConversion.Data})
}


type ChatgptPackage struct {
	Question string `json:"question"`
	Clear bool `json:"clear"`
}

type ChatgptOption struct {
	ParentMessageId string `json:"parentMessageId"`
}

type ChatgptRequest struct {
	Prompt string `json:"prompt"`
	Options ChatgptOption `json:"options"`
}

type ChatgptResponse struct {
	Text string `json:"text"`
	Id string `json:"id"`
}


func GetChatgptAnswer(c *gin.Context) {
	ok := util.LimitIpInterval(c, 5)
	if !ok {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "你问题太频繁了！"})
		return
	}

	err := checkPrivilegeBySession(c)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": err.Error()})
		return
	}

	var chatgptPackage ChatgptPackage
	if c.ShouldBindJSON(&chatgptPackage) != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "请求体格式不对"})
		return
	}

	// 防止单个账号同时访问
	session := sessions.Default(c)
	userName := session.Get("user").(string)
	UserStatus[userName] = true
	conversionPath := fmt.Sprintf("%s/chatgpt/%s.json", ConversionRoot, userName)

	defer delete(UserStatus, userName)

	clear := chatgptPackage.Clear
	if clear {
		delete(UserName2LastPromptId, userName)
		err = os.Remove(conversionPath)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"code": 4001, "data": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"code": 200, "data": "删除成功"})
		return
	}

	question := chatgptPackage.Question
	question = strings.TrimSpace(question)
	if len(question) == 0 {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "输入不能为空！"})
		return
	}

	lastMessageId, ok := UserName2LastPromptId[userName]
	if !ok {
		lastMessageId = ""
	}
	chatgptRequest := ChatgptRequest {
		Prompt: question,
		Options: ChatgptOption{ ParentMessageId: lastMessageId },
	}

	chatgptResponse, err := chatgptProcess(chatgptRequest)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": err.Error()})
		return
	}

	UserName2LastPromptId[userName] = chatgptResponse.Id
	chatgptAnswer := strings.TrimSpace(chatgptResponse.Text)
	if len(chatgptAnswer) == 0 {
		c.JSON(http.StatusOK, gin.H{"code": 4001, "data": "返回值为空，可能是后台出现了问题，不妨重新试一下"})
		return
	}

	
	go func() {
		SaveConversionItem(conversionPath, question, chatgptAnswer)
	}()
	c.JSON(http.StatusOK, gin.H{"code": 200, "data": chatgptAnswer})
}

func SaveConversionItem(conversionPath, userMessage, assistantMessage string) error {
	conversionItem := ConversionItem {
		User: userMessage,
		Assistant: assistantMessage,
	}
	ext, _ := util.CheckFilePath(conversionPath)
	if !ext {
		var conversion ChatgptConversion
		conversion.Data = append(conversion.Data, conversionItem)
		return util.WriteJson(conversionPath, conversion)
	}

	file, err := os.Open(conversionPath)	
	if err != nil {
		return errors.New("打开本地json出错")
	}
	defer file.Close()
	
	data, err := ioutil.ReadAll(file)
	if err != nil {
		return errors.New("读取本地json出错")
	}

	var chatgptConversion ChatgptConversion
	err = json.Unmarshal(data, &chatgptConversion)
	if err != nil {
		return errors.New("解析本地json出错")
	}

	chatgptConversion.Data = append(chatgptConversion.Data, conversionItem)
	err = util.WriteJson(conversionPath, chatgptConversion)
	if err != nil {
		return err
	}
	return nil
}


func chatgptProcess(request ChatgptRequest) (ChatgptResponse, error) {
	var chatgptResponse ChatgptResponse
	// 设置请求体
	jsonData, _ := json.Marshal(request)
	requestsString := string(jsonData)
	requestBody := []byte(requestsString)

	req, err := http.NewRequest("POST", "http://aieasy.top/api/chat-process", bytes.NewBuffer(requestBody))
	if err != nil {
		fmt.Println("获取地址错误")
		return chatgptResponse, errors.New("获取地址错误")
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Host", "aieasy.top")
	req.Header.Set("Origin", "http://aieasy.top")
	req.Header.Set("Referer", "http://aieasy.top/")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36")
	req.Header.Set("Cookie", "ajs_user_id=S50Q9L1A4jbf5g5Rbx9YHdRRn1R2; ajs_anonymous_id=6b0a0b7e-89ef-4cc7-a34e-ad3b573ab5f2")

	// 发送
	client := &http.Client{}
	response, err := client.Do(req)
	
	if err!=nil {
		fmt.Println("登录错误")
	}
	defer response.Body.Close()
	
	// fmt.Println(response.StatusCode)

	decoder := json.NewDecoder(response.Body)
	var id, text string
	for {
		var obj map[string]interface{}
		err := decoder.Decode(&obj)
		if err != nil {
			break // 如果没有更多的JSON对象，则退出循环
		}

		// 处理JSON对象
		id = obj["id"].(string)
		text = obj["text"].(string)
	}

	chatgptResponse.Id = id
	chatgptResponse.Text = text
	return chatgptResponse, nil
}